home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / amiga / sobja.lha / sobja.c < prev    next >
C/C++ Source or Header  |  1992-02-27  |  41KB  |  1,778 lines

  1.  
  2. #define VERSION "SObjA - Version 1.03"
  3.  
  4. #define BANNER \
  5.    "SObjA - Convert object files from Sun to Amiga format."            "\n" \
  6.    "Copyright (C) 1990 - Ray Burr"                                     "\n"
  7.  
  8. /*  This program is free software; you can redistribute it and/or modify
  9.     it under the terms of the GNU General Public License as published by
  10.     the Free Software Foundation; either version 1, or (at your option)
  11.     any later version.
  12.  
  13.     This program is distributed in the hope that it will be useful,
  14.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.     GNU General Public License for more details.
  17.  
  18.     You should have received a copy of the GNU General Public License
  19.     along with this program; if not, write to the Free Software
  20.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22.   --------------------------------------------------------------------------
  23.  
  24.     This code is a temporary (I hope) solution to the problem of getting
  25.   GCC to output object files that can be linked by an Amiga linker.  It is
  26.   not ment as a tool for converting ANY Sun object file to an Amiga object
  27.   file.  It was writen with only GCC v1.37 in mind.  I am not an expert on
  28.   UN*X object files so this code might be on the wierd side... but I
  29.   wouldn't release it unless I thought it had some chance of working
  30.   sometimes.
  31.                                     - Ray Burr (ryb)
  32.  
  33.  
  34.   HISTORY
  35.  
  36.   Ver.  Who      When       What
  37.  
  38.   1.03  ryb      901022     Improved some error checks.  Copies object
  39.                               files that are already in amiga format.
  40.  
  41.   1.02  ryb      900927     Fixed bug in CopySegments().  Was sometimes
  42.                               calling free() on NULL.
  43.  
  44.   1.01  ryb      900917     Combined SObjA and MakeBSS.  Fixed bug in
  45.                               handling files with no common references
  46.                               using '-c' option.  Added '-s' option.  Added
  47.                               error checks.
  48.  
  49.   1.0   ryb      900827     First release.
  50.  
  51. */
  52.  
  53.  
  54. #include <stdio.h>
  55. #include <string.h>
  56. #include <ctype.h>
  57.  
  58. #ifndef unix
  59. #include <stdlib.h>
  60. #endif
  61.  
  62.  
  63. #define CleanExit(m,r) KleanExit(m,r,__LINE__)
  64.  
  65. #define RC_OK   0
  66. #define RC_WARN 10
  67. #define RC_FAIL 20
  68.  
  69. #define FALSE 0
  70. #define TRUE  1
  71.  
  72. #ifndef SEEK_SET
  73. #define SEEK_SET 0
  74. #define SEEK_CUR 1
  75. #define SEEK_END 2
  76. #endif
  77.  
  78. #define MAX_FILENAME_LENGTH 80
  79.  
  80. #define OPTION_PREFIX '-'
  81.  
  82. #define FILENAME_EXTENSION "-amiga"
  83.  
  84. #define BUFFER_SIZE 0x0800
  85.  
  86. #define LOOP for (;;)
  87.  
  88. #define ALLOCATE_MEMORY(pointer, count, size) \
  89.   { \
  90.     (pointer) = (void *)malloc((count) * (size)); \
  91.     if ((pointer) == NULL) \
  92.       CleanExit(NoMemoryErrorMessage, RC_FAIL); \
  93.   }
  94.  
  95. #define WRITE_LONG(longword, file) \
  96.   ((ulongtmp = longword), \
  97.   fwrite((char *)&ulongtmp, 4, 1, file))
  98.  
  99. #define READ_LONG(file) \
  100.   ((fread((char *)&ulongtmp, 4, 1, file) != 1) ? \
  101.    (ferror(file) ? \
  102.     (CleanExit(ReadErrorMessage, RC_FAIL), 0) : \
  103.     EOF) : \
  104.    ulongtmp)
  105.  
  106. /* For debug: (Note that var is evaluated twice.) */
  107. #define PRDEC(var) (printf(#var " = %ld\n",     (long)(var)), (var));
  108. #define PRHEX(var) (printf(#var " = 0x%08lx\n", (long)(var)), (var));
  109.  
  110.  
  111. #define HUNK_UNIT    0x03e7
  112. #define HUNK_NAME    0x03e8
  113. #define HUNK_CODE    0x03e9
  114. #define HUNK_DATA    0x03ea
  115. #define HUNK_BSS     0x03eb
  116. #define HUNK_RELOC32 0x03ec
  117. #define HUNK_RELOC16 0x03ed
  118. #define HUNK_RELOC8  0x03ee
  119. #define HUNK_EXT     0x03ef
  120. #define HUNK_SYMBOL  0x03f0
  121. #define HUNK_END     0x03f2
  122. #define HUNK_HEADER  0x03f3
  123.  
  124. #define EXT_DEF      0x01
  125. #define EXT_ABS      0x02
  126. #define EXT_REF32    0x81
  127. #define EXT_COMMON   0x82
  128. #define EXT_REF16    0x83
  129. #define EXT_REF8     0x84
  130.  
  131.  
  132. struct exec {
  133.   unsigned       a_dynamic:1;
  134.   unsigned       a_toolversion:7;
  135.   unsigned       a_machtype:8;      /* unsigned char  */
  136.   unsigned       a_magic:16;        /* unsigned short */
  137.   unsigned long  a_text;     /* Text segment's size */
  138.   unsigned long  a_data;     /* Data ...            */
  139.   unsigned long  a_bss;      /* BSS  ...            */
  140.   unsigned long  a_syms;     /* Symbol table's size */
  141.   unsigned long  a_entry;
  142.   unsigned long  a_trsize;   /* Text relocation info's size */
  143.   unsigned long  a_drsize;   /* Data ...                    */
  144. };
  145.  
  146. struct reloc_info_68k {
  147.   long     r_address;
  148.   unsigned r_symbolnum:24,
  149.            r_pcrel:1,
  150.            r_length:2,
  151.            r_extern:1,
  152.            r_baserel:1,
  153.            r_jmptable:1,
  154.            r_relative:1,
  155.            poopoo:1;
  156. };
  157.  
  158. #define SUN_MAGIC 0407  /* Octal */
  159.  
  160. #define N_UNDF 0x00
  161. #define N_EXT  0x01
  162. #define N_ABS  0x02
  163. #define N_TEXT 0x04
  164. #define N_DATA 0x06
  165. #define N_BSS  0x08
  166. #define N_TYPE 0x1e
  167.  
  168. struct nlist {
  169.   union {
  170.     char *n_name;
  171.     long n_strx;
  172.   } n_un;
  173.   unsigned char n_type;
  174.   char          n_other;
  175.   short         n_desc;
  176.   unsigned long n_value;
  177. };
  178.  
  179.  
  180. static char *DefaultFilenameExtension = FILENAME_EXTENSION;
  181. static char *DefaultCommonFilename = "sobja-common";
  182. static char *DefaultBssFilename = "bss.o" FILENAME_EXTENSION;
  183.  
  184. static char *NoMemoryErrorMessage = "Can't allocate memory.";
  185. static char *ReadErrorMessage = "Can't read input file.";
  186.  
  187. static char *ProgramName;
  188. static FILE *InFile, *OutFile;
  189. static struct reloc_info_68k *TextRelocInfo, *DataRelocInfo;
  190. static struct nlist *SymbolTable;
  191. static unsigned long StringTableSize;
  192. static char *StringTable;
  193. static long SymbolCount;
  194. static long TextRelocCount;
  195. static long DataRelocCount;
  196. static unsigned long ulongtmp;
  197. static int CodeHunkNumber, DataHunkNumber, BssHunkNumber;
  198. static long *DataRefListRoots, *DataRefLists;
  199. static long *TextRefListRoots, *TextRefLists;
  200. static long *DataRefXRef;
  201. static long *BufferSizes;
  202. static short CommonOption, VerboseOption, MakeBSSOption;
  203. static short DeleteCommonOption, SymbolsOption;
  204. static char *CommonFilename;
  205. static char *InFileName, *OutFileName;
  206. static struct exec WorkingExec;
  207. static FILE *CommonFile;
  208. static long *CommonNames;
  209.  
  210.  
  211. static unsigned long *MkBssSizes;
  212. static char **MkBssNames;
  213. static char *StringTable;
  214. static long *XRef;
  215.  
  216.  
  217. static unsigned char Buffer[BUFFER_SIZE];
  218.  
  219. static int WordLength[] = { 1, 2, 4, 0 };
  220.  
  221.  
  222. char *SourceFilename = __FILE__;
  223.  
  224. static void
  225. KleanExit(mesg, rc, line)
  226. char *mesg;
  227. int rc;
  228. int line;
  229. {
  230.  
  231.  
  232.   if (mesg != NULL)
  233.     fprintf(stderr, "%s line %d: %s\n", SourceFilename, line, mesg);
  234.   else
  235.     if (rc != 0)
  236.       fprintf(stderr, "%s line %d: ReturnCode = %d\n",
  237.               SourceFilename, line, rc);
  238.  
  239.  
  240.   if (InFile     != NULL) fclose(InFile);
  241.   if (OutFile    != NULL) fclose(OutFile);
  242.   if (CommonFile != NULL) fclose(CommonFile);
  243.  
  244.   if (TextRelocInfo    != NULL) free(TextRelocInfo);
  245.   if (DataRelocInfo    != NULL) free(DataRelocInfo);
  246.   if (SymbolTable      != NULL) free(SymbolTable);
  247.   if (StringTable      != NULL) free(StringTable);
  248.   if (TextRefListRoots != NULL) free(TextRefListRoots);
  249.   if (TextRefLists     != NULL) free(TextRefLists);
  250.   if (DataRefListRoots != NULL) free(DataRefListRoots);
  251.   if (DataRefLists     != NULL) free(DataRefLists);
  252.   if (DataRefXRef      != NULL) free(DataRefXRef);
  253.   if (BufferSizes      != NULL) free(BufferSizes);
  254.   if (CommonNames      != NULL) free(CommonNames);
  255.  
  256.   if (MkBssSizes  != NULL) free(MkBssSizes);
  257.   if (MkBssNames  != NULL) free(MkBssNames);
  258.   if (StringTable != NULL) free(StringTable);
  259.   if (XRef        != NULL) free(XRef);
  260.  
  261.   exit(rc);
  262. }
  263.  
  264.  
  265. void
  266. OpenOutputFile()
  267. {
  268.   if (OutFile != NULL) return;
  269.  
  270.   OutFile = fopen(OutFileName, "w");
  271.  
  272.   if (OutFile == NULL) {
  273.     fprintf(stderr, "Can't open file \"%s\" for output.\n", OutFileName);
  274.     CleanExit(NULL, RC_FAIL);
  275.   }
  276. }
  277.  
  278.  
  279. static DataRefSortCompare(element1, element2)
  280. long *element1, *element2;
  281. {
  282.   static struct reloc_info_68k *RelocInfo;
  283.  
  284.   if (element1 == NULL) {
  285.     RelocInfo = (struct reloc_info_68k *)element2;
  286.     return 0;
  287.   }
  288.  
  289.   return RelocInfo[*element1].r_address - RelocInfo[*element2].r_address;
  290. }
  291.  
  292.  
  293. /*
  294.     CopySegments - Copy a segment from the input to the output changing
  295.         the relocated refrences as aproporiate.
  296.  
  297.         The data is copied through in blocks of about BUFFER_SIZE bytes but
  298.     the actual sizes of the blocks are adjusted so that no relocated words
  299.     are split.  The 'type' is argument N_TEXT or N_DATA and determines
  300.     which block is copied through. CopySegments() does a seek on the input
  301.     file to the correct segment.  Then it copies the segment through
  302.     creating a hunk of the same type as the input segment (N_TEXT ==
  303.     HUNK_CODE and N_DATA == HUNK_DATA).
  304.  
  305. */
  306.  
  307. static void
  308. CopySegments(type)
  309. int type;
  310. {
  311.   long i;
  312.   long SeekPosition;
  313.   long SegmentLength;
  314.   long BlockSize;
  315.   unsigned long HunkType;
  316.   long TextOffset;
  317.   long RelocCount;
  318.   long BufferBlockNumber;
  319.   long BytesDontFit;
  320.   int DataRefCount;
  321.   int BufferBlockCount;
  322.   int DataRefIndex;
  323.   long DataRefAddress;
  324.   int BufferOffset;
  325.   int BytesInWord;
  326.   long BufferStartAddress;
  327.   struct reloc_info_68k *RelocInfo;
  328.  
  329.   /* Set things up for what segment we're working on. */
  330.   if (type == N_TEXT) {
  331.     SeekPosition = sizeof(struct exec);
  332.     SegmentLength = WorkingExec.a_text;
  333.     HunkType = HUNK_CODE;
  334.     RelocInfo = TextRelocInfo;
  335.     RelocCount = TextRelocCount;
  336.     TextOffset = 0;
  337.   }
  338.   else {
  339.     SeekPosition = sizeof(struct exec) + WorkingExec.a_text;
  340.     SegmentLength = WorkingExec.a_data;
  341.     HunkType = HUNK_DATA;
  342.     RelocInfo = DataRelocInfo;
  343.     RelocCount = DataRelocCount;
  344.     TextOffset = WorkingExec.a_text;
  345.   }
  346.  
  347.   /* If the segment is empty, don't bother. */
  348.   if (SegmentLength == 0) return;
  349.  
  350.   if (RelocCount != 0)
  351.     ALLOCATE_MEMORY(DataRefXRef, RelocCount, 4);
  352.  
  353.   /*
  354.     The references to this object file's own DATA and BSS segments needs
  355.     to be changed because in Sun object files these references are
  356.     relative to the TEXT segment while in Amiga object files they are
  357.     relative to the segment (hunk) they are referencing.
  358.     This code does it's own buffering and it modifies each relocatable
  359.     reference as it goes.  It figures the size of the blocks in a way
  360.     that keeps words from being split between blocks.
  361.   */
  362.  
  363.   BufferBlockCount = (SegmentLength + BUFFER_SIZE - 1) / BUFFER_SIZE;
  364.  
  365.   ALLOCATE_MEMORY(BufferSizes, BufferBlockCount + 1, 4);
  366.  
  367.   for (i = 0; i < BufferBlockCount - 1; ++i)
  368.     BufferSizes[i] = BUFFER_SIZE;
  369.  
  370.   BufferSizes[BufferBlockCount - 1] = SegmentLength % BUFFER_SIZE;
  371.  
  372.   DataRefCount = 0;
  373.  
  374.   for (i = 0; i < RelocCount; ++i) {
  375.  
  376.     if (RelocInfo[i].r_extern == 0 &&
  377.         ((RelocInfo[i].r_symbolnum & N_TYPE) == N_BSS ||
  378.          (RelocInfo[i].r_symbolnum & N_TYPE) == N_DATA)) {
  379.  
  380.       DataRefAddress = RelocInfo[i].r_address;
  381.       BytesInWord = WordLength[RelocInfo[i].r_length];
  382.  
  383.       if (DataRefAddress >= SegmentLength - BytesInWord) {
  384.         fprintf(stderr, "Relocation beyond end of hunk.\n");
  385.         fprintf(stderr, "  RelocationOffset = 0x%lx ", DataRefAddress);
  386.         fprintf(stderr, "in segment type %d\n",
  387.                 (int)(RelocInfo[i].r_symbolnum & N_TYPE));
  388.         fprintf(stderr, "  RelocInfo entry number %ld.\n", i);
  389.         CleanExit(NULL, RC_FAIL);
  390.       }
  391.  
  392.       DataRefXRef[DataRefCount++] = i;
  393.  
  394.       /* Since we know this word must be at least partially in this block,
  395.          find out how many (if any) bytes are past the end of the block. */
  396.  
  397.       BytesDontFit = BytesInWord - (BUFFER_SIZE
  398.                                     - (DataRefAddress - TextOffset)
  399.                                     % BUFFER_SIZE);
  400.  
  401.       if (BytesDontFit > 0) {
  402.  
  403.         BufferBlockNumber = (DataRefAddress - TextOffset) / BUFFER_SIZE;
  404.  
  405.         /* Extend this block so that the word will fit, and shorten the
  406.            next one so that the end of the next doesn't change. */
  407.  
  408.         BufferSizes[BufferBlockNumber    ] += BytesDontFit;
  409.         BufferSizes[BufferBlockNumber + 1] -= BytesDontFit;
  410.       }
  411.     }
  412.   }
  413.  
  414.   /* Tell the compare function what array to use. */
  415.   DataRefSortCompare(NULL, RelocInfo);
  416.  
  417.   /* Sort the refrences to the order they appear in the file. */
  418.   qsort((char *)DataRefXRef, DataRefCount, 4, DataRefSortCompare);
  419.  
  420.   if (VerboseOption > 0) {
  421.  
  422.     printf("Data and BSS Segment Reference Offsets:\n");
  423.  
  424.     for (i = 0; i < DataRefCount; ++i) {
  425.  
  426.       printf("  %08lX\n", RelocInfo[DataRefXRef[i]].r_address);
  427.     }
  428.  
  429.     printf("Buffer Sizes:\n");
  430.  
  431.     for (i = 0; i < BufferBlockCount; ++i) {
  432.  
  433.       printf("  %08lX\n", BufferSizes[i]);
  434.     }
  435.   }
  436.  
  437.   /* Go to the start of the segment. */
  438.   fseek(InFile, SeekPosition, SEEK_SET);
  439.  
  440.   WRITE_LONG(HunkType, OutFile);
  441.  
  442.   WRITE_LONG((SegmentLength + 3) / 4, OutFile);
  443.  
  444.   DataRefIndex = 0;
  445.   BufferStartAddress = 0;
  446.  
  447.   for (BufferBlockNumber = 0;
  448.        BufferBlockNumber < BufferBlockCount;
  449.        ++BufferBlockNumber) {
  450.  
  451.     BlockSize = BufferSizes[BufferBlockNumber];
  452.  
  453.     if (fread(Buffer, 1, BlockSize, InFile) != BlockSize)
  454.       CleanExit("Can't read segment.", RC_FAIL);
  455.  
  456.     while (DataRefIndex < DataRefCount) {
  457.  
  458.       DataRefAddress =
  459.         RelocInfo[DataRefXRef[DataRefIndex]].r_address;
  460.  
  461.       BufferOffset = DataRefAddress - BufferStartAddress;
  462.  
  463.       if (BufferOffset >= BlockSize) break;
  464.  
  465.       ulongtmp = 0;
  466.  
  467.       BytesInWord =
  468.         WordLength[RelocInfo[DataRefXRef[DataRefIndex]].r_length];
  469.  
  470.       for (i = 0; i < BytesInWord; ++i)
  471.         ulongtmp = (ulongtmp << 8) | Buffer[BufferOffset++];
  472.  
  473.       if (VerboseOption > 0)
  474.         printf("[%08lX]\n", ulongtmp);
  475.  
  476.       ulongtmp -= WorkingExec.a_text;
  477.  
  478.       if (RelocInfo[DataRefXRef[DataRefIndex]].r_symbolnum == N_BSS)
  479.         ulongtmp -= WorkingExec.a_data;
  480.  
  481.       for (i = 1; i <= BytesInWord; ++i) {
  482.         Buffer[BufferOffset - i] = ulongtmp & 0xff;
  483.         ulongtmp >>= 8;
  484.       }
  485.  
  486.       ++DataRefIndex;
  487.     }
  488.  
  489.     if (fwrite(Buffer, 1, BlockSize, OutFile) != BlockSize)
  490.       CleanExit("Can't write segment.", RC_FAIL);
  491.  
  492.     BufferStartAddress += BlockSize;
  493.   }
  494.  
  495.   if (DataRefXRef != NULL) {    /* Free this only if it was allocated. */
  496.  
  497.     free(DataRefXRef);
  498.     DataRefXRef = NULL;
  499.   }
  500.  
  501.   free(BufferSizes);
  502.   BufferSizes = NULL;
  503. }
  504.  
  505.  
  506. /*
  507.     OutputSymbolName - Output a string to OutFile in the format that Amiga
  508.         object files use... Longword of length, then the string padded with
  509.         zeros.  The upper byte of the length longword is set to 'type'.
  510.  
  511. */
  512.  
  513. static void
  514. OutputSymbolName(symbolname, type)
  515. char *symbolname;
  516. unsigned char type;
  517. {
  518.   int SymbolNameLength;
  519.  
  520.   SymbolNameLength = strlen(symbolname);
  521.  
  522.   WRITE_LONG(((SymbolNameLength + 3) / 4) | (type << 24), OutFile);
  523.  
  524.   fwrite(symbolname, 1, SymbolNameLength, OutFile);
  525.  
  526.   if (SymbolNameLength % 4 != 0) {
  527.  
  528.     ulongtmp = 0;
  529.     fwrite((char *)&ulongtmp, 1,
  530.            3 - (SymbolNameLength + 3) % 4, OutFile);
  531.   }
  532. }
  533.  
  534.  
  535. /*
  536.     OutputRelocInfo - Generates the HUNK_RELOCxx blocks for a hunk.
  537.  
  538.  */
  539.  
  540. static void
  541. OutputRelocInfo(relocinfo, reloccount)
  542. struct reloc_info_68k *relocinfo;
  543. int reloccount;
  544. {
  545.   int FoundAnyOfType, FoundAnyOfBits, Bits;
  546.   long i, ReferenceCount, SeekPosition;
  547.   int NType, ReferencedHunk, Type;
  548.   unsigned long HunkType, RelocAddress;
  549.  
  550.   int SegmentLength;
  551.   SegmentLength = (relocinfo == TextRelocInfo) ?    /* Yes, this is bad. */
  552.                   WorkingExec.a_text :
  553.                   WorkingExec.a_data;
  554.  
  555.   for (Bits = 0; Bits < 3; ++Bits) {
  556.  
  557.     FoundAnyOfBits = FALSE;
  558.  
  559.     for (Type = 0; Type < 3; ++Type) {
  560.  
  561.       switch (Type) {
  562.  
  563.         case 0:
  564.           ReferencedHunk = CodeHunkNumber;
  565.           NType = N_TEXT;
  566.           break;
  567.         case 1:
  568.           ReferencedHunk = DataHunkNumber;
  569.           NType = N_DATA;
  570.           break;
  571.         default:
  572.           ReferencedHunk = BssHunkNumber;
  573.           NType = N_BSS;
  574.       }
  575.  
  576.       FoundAnyOfType = FALSE;
  577.       ReferenceCount = 0;
  578.  
  579.       for (i = 0; i < reloccount; ++i) {
  580.  
  581.         if (relocinfo[i].r_extern    == 0 &&
  582.             relocinfo[i].r_length    == Bits &&
  583.             (relocinfo[i].r_symbolnum & N_TYPE) == NType) {
  584.  
  585.           if (!FoundAnyOfType) {
  586.  
  587.             if (!FoundAnyOfBits) {
  588.  
  589.               FoundAnyOfBits = TRUE;
  590.  
  591.               switch (Bits) {
  592.                 case 0:  HunkType = HUNK_RELOC8;  break;
  593.                 case 1:  HunkType = HUNK_RELOC16; break;
  594.                 default: HunkType = HUNK_RELOC32; break;
  595.               }
  596.  
  597.               WRITE_LONG(HunkType, OutFile);
  598.             }
  599.  
  600.  
  601.             FoundAnyOfType = TRUE;
  602.  
  603.             SeekPosition = ftell(OutFile);
  604.  
  605.             WRITE_LONG(0, OutFile);
  606.  
  607.             WRITE_LONG(ReferencedHunk, OutFile);
  608.           }
  609.  
  610.           RelocAddress = relocinfo[i].r_address;
  611.  
  612.           WRITE_LONG(RelocAddress, OutFile);
  613.  
  614.           ++ReferenceCount;
  615.         }
  616.       }
  617.  
  618.       if (FoundAnyOfType) {
  619.  
  620.         fseek(OutFile, SeekPosition, SEEK_SET);
  621.  
  622.         WRITE_LONG(ReferenceCount, OutFile);
  623.  
  624.         fseek(OutFile, 0L, SEEK_END);
  625.       }
  626.     }
  627.  
  628.     if (FoundAnyOfBits)
  629.       WRITE_LONG(0, OutFile);
  630.   }
  631. }
  632.  
  633.  
  634. /*
  635.     OutputExternDefInfo - Generates the EXT_DEF part of a HUNK_EXT for a
  636.         hunk.
  637.  
  638. */
  639.  
  640. static OutputExternDefInfo(type, foundany)
  641. int type, foundany;
  642. {
  643.   long i;
  644.   unsigned long Value;
  645.  
  646.   for (i = 0; i < SymbolCount; ++i) {
  647.  
  648.     if ((SymbolTable[i].n_type & (N_TYPE | N_EXT)) == (type | N_EXT)) {
  649.  
  650.       if (!foundany) {
  651.  
  652.         WRITE_LONG(HUNK_EXT, OutFile);
  653.  
  654.         foundany = TRUE;
  655.       }
  656.  
  657.       OutputSymbolName(SymbolTable[i].n_un.n_name, EXT_DEF);
  658.  
  659.       Value = SymbolTable[i].n_value;
  660.       if (type == N_DATA) Value -= WorkingExec.a_text;
  661.       if (type == N_BSS) {
  662.         printf("Found a BSS XDef!\n");
  663.         Value -= WorkingExec.a_text + WorkingExec.a_data;
  664.       }
  665.  
  666.       WRITE_LONG(Value, OutFile);
  667.     }
  668.   }
  669.  
  670.   return foundany;
  671. }
  672.  
  673.  
  674. /*
  675.     OutputExternInfo - Generates the EXT_REFxx blocks for a hunk.
  676.  
  677. */
  678.  
  679. static void
  680. OutputExternInfo(relocinfo, reflistroots, reflists, type)
  681. struct reloc_info_68k *relocinfo;
  682. long *reflistroots, *reflists;
  683. int type;
  684. {
  685.   int FoundAny, Bits, BitType;
  686.   long i, x, Index;
  687.   unsigned long RefAddress, RefAddressLimit;
  688.  
  689.  
  690.   for (Bits = 0; Bits < 3; ++Bits) {
  691.  
  692.     RefAddressLimit =
  693.       (type == N_TEXT ? WorkingExec.a_text : WorkingExec.a_data)
  694.        - WordLength[Bits];
  695.  
  696.     switch (Bits) {
  697.  
  698.       case 0:  BitType = EXT_REF8;  break;
  699.       case 1:  BitType = EXT_REF16; break;
  700.       default: BitType = EXT_REF32; break;
  701.     }
  702.  
  703.     FoundAny = FALSE;
  704.  
  705.     for (i = 0; i < SymbolCount; ++i) {
  706.  
  707.       if (reflistroots[i] >= 0 ) {
  708.  
  709.         x = 0;
  710.         Index = reflistroots[i];
  711.  
  712.         while (Index >= 0) {
  713.  
  714.           if (relocinfo[Index].r_length == Bits) ++x;
  715.  
  716.           Index = reflists[Index];
  717.         }
  718.  
  719.         if (x != 0) {
  720.  
  721.           if (!FoundAny) {
  722.  
  723.             WRITE_LONG(HUNK_EXT, OutFile);
  724.  
  725.             FoundAny = TRUE;
  726.           }
  727.  
  728.           OutputSymbolName(SymbolTable[i].n_un.n_name, BitType);
  729.  
  730.           WRITE_LONG(x, OutFile);
  731.  
  732.           Index = reflistroots[i];
  733.  
  734.           while (Index >= 0) {
  735.  
  736.             if (relocinfo[Index].r_length == Bits) {
  737.  
  738.               RefAddress = relocinfo[Index].r_address;
  739.  
  740.               if (RefAddress > RefAddressLimit) {
  741.                 fprintf(stderr, "Reference beyond end of hunk.\n");
  742.                 fprintf(stderr, "  ReferenceOffset = 0x%lx\n", RefAddress);
  743.                 fprintf(stderr, "  RelocInfo entry number %ld.\n", Index);
  744.                 CleanExit(NULL, RC_FAIL);
  745.               }
  746.  
  747.               WRITE_LONG(RefAddress, OutFile);
  748.             }
  749.  
  750.             Index = reflists[Index];
  751.           }
  752.         }
  753.       }
  754.     }
  755.   }
  756.  
  757.   FoundAny = OutputExternDefInfo(type, FoundAny);
  758.  
  759.   if (FoundAny)
  760.     WRITE_LONG(0, OutFile);
  761.  
  762. }
  763.  
  764.  
  765. static void
  766. OutputSymbols(type)
  767. unsigned long type;
  768. {
  769.   long i;
  770.   unsigned long TextOffset;
  771.   int FoundAny;
  772.  
  773.   switch (type) {
  774.  
  775.     case N_TEXT:
  776.       TextOffset = 0;
  777.       break;
  778.  
  779.     case N_DATA:
  780.       TextOffset = WorkingExec.a_text;
  781.       break;
  782.  
  783.     case N_BSS:
  784.       TextOffset = WorkingExec.a_text + WorkingExec.a_data;
  785.       break;
  786.   }
  787.  
  788.   FoundAny = FALSE;
  789.  
  790.   for (i = 0; i < SymbolCount; ++i) {
  791.  
  792.     if ((SymbolTable[i].n_type & N_TYPE) == type &&
  793.         SymbolTable[i].n_un.n_name != NULL) {
  794.  
  795.       if (!FoundAny) {
  796.  
  797.         FoundAny = TRUE;
  798.  
  799.         WRITE_LONG(HUNK_SYMBOL, OutFile);
  800.       }
  801.  
  802.       OutputSymbolName(SymbolTable[i].n_un.n_name, 0);
  803.  
  804.       WRITE_LONG(SymbolTable[i].n_value - TextOffset, OutFile);
  805.     }
  806.   }
  807.  
  808.   if (FoundAny)
  809.     WRITE_LONG(0, OutFile);
  810. }
  811.  
  812.  
  813. /*
  814.     OutputCommonAsBss
  815.  
  816. */
  817.  
  818. static void
  819. OutputCommonAsBss()
  820. {
  821.   long i, CommonBssSize, CommonBssOffset;
  822.  
  823.   CommonBssSize = 0;
  824.  
  825.   for (i = 0; i < SymbolCount; ++i) {
  826.  
  827.     if ((SymbolTable[i].n_type & (N_TYPE | N_EXT)) == (N_UNDF | N_EXT) &&
  828.         SymbolTable[i].n_value != 0)
  829.       CommonBssSize += SymbolTable[i].n_value;
  830.   }
  831.  
  832.   if (CommonBssSize == 0) return;
  833.  
  834.   WRITE_LONG(HUNK_BSS,      OutFile);
  835.   WRITE_LONG(CommonBssSize, OutFile);
  836.   WRITE_LONG(HUNK_EXT,      OutFile);
  837.  
  838.   CommonBssOffset = 0;
  839.  
  840.   for (i = 0; i < SymbolCount; ++i) {
  841.  
  842.     if ((SymbolTable[i].n_type & (N_TYPE | N_EXT)) == (N_UNDF | N_EXT) &&
  843.         SymbolTable[i].n_value != 0) {
  844.  
  845.       OutputSymbolName(SymbolTable[i].n_un.n_name, EXT_DEF);
  846.  
  847.       WRITE_LONG(CommonBssOffset, OutFile);
  848.  
  849.       CommonBssOffset += SymbolTable[i].n_value;
  850.     }
  851.   }
  852.  
  853.   WRITE_LONG(0, OutFile);
  854.  
  855.   WRITE_LONG(HUNK_END, OutFile);
  856.  
  857.   return;
  858. }
  859.  
  860.  
  861. static void
  862. StupidCommonKludge()
  863. {
  864.   long i, NameIndex, SizeEntryCount, StringCharCount, SeekPosition;
  865.   char *SymbolName;
  866.   int SymbolNameLength;
  867.  
  868.   if (CommonFilename == NULL) CommonFilename = DefaultCommonFilename;
  869.  
  870.   if (CommonOption == 1)
  871.     CommonFile = fopen(CommonFilename, "r+");
  872.   else
  873.     CommonFile = fopen(CommonFilename, "w+");
  874.  
  875.   if (CommonFile == NULL)
  876.     CleanExit("Can't open the stupid common file thing.", RC_FAIL);
  877.  
  878.   fseek(CommonFile, 0L, SEEK_END);
  879.  
  880.   SeekPosition = ftell(CommonFile);
  881.  
  882.   WRITE_LONG(0, CommonFile);
  883.   WRITE_LONG(0, CommonFile);
  884.  
  885.   SizeEntryCount  = 0;
  886.  
  887.   for (i = 0; i < SymbolCount; ++i) {
  888.  
  889.     if ((SymbolTable[i].n_type & (N_TYPE | N_EXT)) == (N_UNDF | N_EXT) &&
  890.         SymbolTable[i].n_value != 0) {
  891.  
  892.       WRITE_LONG(SymbolTable[i].n_value, CommonFile);
  893.  
  894.       ++SizeEntryCount;
  895.     }
  896.   }
  897.  
  898.   StringCharCount = 0;
  899.  
  900.   if (SizeEntryCount != 0) {
  901.  
  902.     ALLOCATE_MEMORY(CommonNames, SizeEntryCount, 4);
  903.  
  904.     NameIndex = 0;
  905.  
  906.     for (i = 0; i < SymbolCount; ++i) {
  907.  
  908.       if ((SymbolTable[i].n_type & (N_TYPE | N_EXT)) == (N_UNDF | N_EXT) &&
  909.           SymbolTable[i].n_value != 0) {
  910.  
  911.         SymbolName = SymbolTable[i].n_un.n_name;
  912.         SymbolNameLength = strlen(SymbolName);
  913.  
  914.         fwrite(SymbolName, 1, SymbolNameLength + 1, CommonFile);
  915.  
  916.         CommonNames[NameIndex++] = StringCharCount;
  917.  
  918.         StringCharCount += SymbolNameLength + 1;
  919.       }
  920.     }
  921.  
  922.     fwrite((char *)CommonNames, 4, SizeEntryCount, CommonFile);
  923.  
  924.     free(CommonNames);
  925.     CommonNames = NULL;
  926.   }
  927.  
  928.   fseek(CommonFile, SeekPosition, SEEK_SET);
  929.  
  930.   WRITE_LONG(SizeEntryCount, CommonFile);
  931.   WRITE_LONG(StringCharCount, CommonFile);
  932.  
  933.   if (ferror(CommonFile) != 0)
  934.     CleanExit("Error accessing the CommonFile.", RC_FAIL);
  935.  
  936.   fclose(CommonFile);
  937.   CommonFile = NULL;
  938. }
  939.  
  940.  
  941. static void
  942. FindRefs(type)
  943. int type;
  944. {
  945.   long i, RelocCount;
  946.   long *RefListRoots, *RefLists;
  947.   struct reloc_info_68k *RelocInfo;
  948.  
  949.   if (type == N_TEXT) {
  950.     RelocInfo = TextRelocInfo;
  951.     RelocCount = TextRelocCount;
  952.     RefLists = TextRefLists;
  953.     RefListRoots = TextRefListRoots;
  954.   }
  955.   else {
  956.     RelocInfo = DataRelocInfo;
  957.     RelocCount = DataRelocCount;
  958.     RefLists = DataRefLists;
  959.     RefListRoots = DataRefListRoots;
  960.   }
  961.  
  962.  
  963.   for (i = 0; i < RelocCount; ++i) {
  964.  
  965.     if (RelocInfo->r_pcrel != 0)
  966.       printf("Warning: pcrel bit set in relocation info.\n");
  967.  
  968.     if (RelocInfo->r_baserel != 0)
  969.       printf("Warning: baserel bit set in relocation info.\n");
  970.  
  971.     if (RelocInfo->r_jmptable != 0)
  972.       printf("Warning: jmptable bit set in relocation info.\n");
  973.  
  974.     if (RelocInfo->r_relative != 0)
  975.       printf("Warning: relative bit set in relocation info.\n");
  976.  
  977.     if (RelocInfo->r_extern != 0) {
  978.  
  979.       RefLists[i] = RefListRoots[RelocInfo->r_symbolnum];
  980.       RefListRoots[RelocInfo->r_symbolnum] = i;
  981.     }
  982.  
  983.     ++RelocInfo;
  984.   }
  985. }
  986.  
  987.  
  988. int
  989. CopyIfAmigaObject()
  990. {
  991.   unsigned long BlockSize, NameLength;
  992.  
  993.   OpenOutputFile();
  994.  
  995.   fseek(InFile, 0, SEEK_SET);
  996.  
  997.   /* If it doesn't start with HUNK_UNIT, can't be an amiga object file. */
  998.   if (READ_LONG(InFile) != HUNK_UNIT)
  999.     return FALSE;
  1000.  
  1001.   /* Make sure the input file is not an executable. */
  1002.   NameLength = READ_LONG(InFile) * 4;
  1003.   fseek(InFile, NameLength, SEEK_CUR);
  1004.   if (READ_LONG(InFile) == HUNK_HEADER)
  1005.     return FALSE;
  1006.  
  1007.   fseek(InFile, 0, SEEK_SET);
  1008.  
  1009.   LOOP {
  1010.  
  1011.     BlockSize = fread(Buffer, 1 , BUFFER_SIZE, InFile);
  1012.     if (BlockSize == 0) break;
  1013.  
  1014.     fwrite(Buffer, 1, BlockSize, OutFile);
  1015.     if (ferror(OutFile))
  1016.       CleanExit("Error writing output file.", RC_FAIL);
  1017.  
  1018.   }
  1019.  
  1020.   if (ferror(InFile))
  1021.     CleanExit(ReadErrorMessage, RC_FAIL);
  1022.  
  1023.   return TRUE;
  1024. }
  1025.  
  1026.  
  1027. static void
  1028. Usage()
  1029. {
  1030.  
  1031.   fprintf(stderr, BANNER
  1032. "Usage: %s [-v] {[-s] [{[-c[Common-Filename]|-C[Common-Filename]} | -b]\n"
  1033. "         Input-Filename [Output-Filename]} | {-m[d] [-cInput-Filename]\n"
  1034. "         [Output-Filename]}\n",
  1035.   ProgramName);
  1036.  
  1037.   CleanExit(NULL, RC_OK);
  1038. }
  1039.  
  1040.  
  1041. static void
  1042. MkBssUsage()
  1043. {
  1044.   fprintf(stderr, BANNER
  1045. "Usage: %s Input-Filename Output-Filename\n",
  1046.   ProgramName);
  1047.  
  1048.   CleanExit(NULL, RC_FAIL);
  1049. }
  1050.  
  1051.  
  1052. static int
  1053. CompareNames(element1, element2)
  1054. long *element1, *element2;
  1055. {
  1056.  
  1057.   return strcmp(MkBssNames[*element1], MkBssNames[*element2]);
  1058. }
  1059.  
  1060.  
  1061. void
  1062. MakeBSS()
  1063. {
  1064.   long i;
  1065.   char *Name;
  1066.   int MaxComm;
  1067.   unsigned long Offset;
  1068.   long HunkSizeSeekPos;
  1069.   unsigned long *SizesNow;
  1070.   char **NamesNow;
  1071.   char *StringTableNow;
  1072.   long SizeEntryCount, StringCharCount;
  1073.   long TotalEntryCount, TotalStringLength;
  1074.  
  1075.   printf("Making BSS file.\n");
  1076.  
  1077.   InFile = fopen(InFileName, "r");
  1078.  
  1079.   if (InFile == NULL)
  1080.     CleanExit("Can't open input file.", RC_FAIL);
  1081.  
  1082.   TotalEntryCount = 0;
  1083.   TotalStringLength = 0;
  1084.  
  1085.   LOOP {
  1086.  
  1087.     SizeEntryCount = READ_LONG(InFile);
  1088.  
  1089.     if (feof(InFile)) break;
  1090.  
  1091.     StringCharCount = READ_LONG(InFile);
  1092.  
  1093.     if (SizeEntryCount == 0) continue;
  1094.  
  1095.     TotalEntryCount   += SizeEntryCount;
  1096.     TotalStringLength += StringCharCount;
  1097.  
  1098.     fseek(InFile, SizeEntryCount * 8 + StringCharCount, SEEK_CUR);
  1099.   }
  1100.  
  1101.   if (TotalEntryCount != 0) {
  1102.  
  1103.     ALLOCATE_MEMORY(MkBssSizes, TotalEntryCount, 4);
  1104.     ALLOCATE_MEMORY(MkBssNames, TotalEntryCount, 4);
  1105.     ALLOCATE_MEMORY(StringTable, TotalStringLength, 1);
  1106.     ALLOCATE_MEMORY(XRef, TotalEntryCount, 4);
  1107.  
  1108.     SizesNow       = MkBssSizes;
  1109.     NamesNow       = MkBssNames;
  1110.     StringTableNow = StringTable;
  1111.  
  1112.     fseek(InFile, 0L, SEEK_SET);
  1113.  
  1114.     LOOP {
  1115.  
  1116.       SizeEntryCount = READ_LONG(InFile);
  1117.  
  1118.       if (feof(InFile)) break;
  1119.  
  1120.       StringCharCount = READ_LONG(InFile);
  1121.  
  1122.       fread((char *)SizesNow, 4, SizeEntryCount, InFile);
  1123.  
  1124.       fread(StringTableNow, 1, StringCharCount, InFile);
  1125.  
  1126.       fread((char *)NamesNow, 4, SizeEntryCount, InFile);
  1127.  
  1128.       if (ferror(InFile))
  1129.         CleanExit(ReadErrorMessage, RC_FAIL);
  1130.  
  1131.       for (i = 0; i < SizeEntryCount; ++i)
  1132.         NamesNow[i] = (unsigned long)NamesNow[i] + StringTableNow;
  1133.  
  1134.       SizesNow       += SizeEntryCount;
  1135.       NamesNow       += SizeEntryCount;
  1136.       StringTableNow += StringCharCount;
  1137.     }
  1138.  
  1139.     for (i = 0; i < TotalEntryCount; ++i)
  1140.       XRef[i] = i;
  1141.  
  1142.     qsort((char *)XRef, TotalEntryCount, 4, CompareNames);
  1143.   }
  1144.  
  1145.   OutFile = fopen(OutFileName, "w");
  1146.  
  1147.   if (OutFile == NULL)
  1148.     CleanExit("Can't open output file.", RC_FAIL);
  1149.  
  1150.   WRITE_LONG(HUNK_UNIT, OutFile);
  1151.  
  1152.   WRITE_LONG(0, OutFile);
  1153.  
  1154.   if (TotalEntryCount != 0) {
  1155.  
  1156.     WRITE_LONG(HUNK_BSS, OutFile);
  1157.  
  1158.     HunkSizeSeekPos = ftell(OutFile);
  1159.  
  1160.     WRITE_LONG(0, OutFile);
  1161.  
  1162.     WRITE_LONG(HUNK_EXT, OutFile);
  1163.  
  1164.     i = 0;
  1165.     Offset = 0;
  1166.  
  1167.     LOOP {
  1168.  
  1169.       Name = MkBssNames[XRef[i]];
  1170.       MaxComm = MkBssSizes[XRef[i]];
  1171.  
  1172.       ++i;
  1173.  
  1174.       if (i > TotalEntryCount) break;
  1175.  
  1176.       while(strcmp(Name, MkBssNames[XRef[i]]) == 0 &&
  1177.             i <= TotalEntryCount) {
  1178.  
  1179.         if (MkBssSizes[XRef[i]] > MaxComm)
  1180.           MaxComm = MkBssSizes[XRef[i]];
  1181.  
  1182.         ++i;
  1183.       }
  1184.  
  1185.    /* printf("0x%08lX %s\n", MaxComm, Name); */
  1186.  
  1187.       OutputSymbolName(Name, EXT_DEF);
  1188.  
  1189.       WRITE_LONG(Offset, OutFile);
  1190.  
  1191.       Offset += MaxComm;
  1192.     }
  1193.  
  1194.     WRITE_LONG(0, OutFile);
  1195.   }
  1196.  
  1197.   WRITE_LONG(HUNK_END, OutFile);
  1198.  
  1199.   if (TotalEntryCount != 0) {
  1200.  
  1201.     fseek(OutFile, HunkSizeSeekPos, SEEK_SET);
  1202.  
  1203.     WRITE_LONG((Offset + 3) / 4, OutFile);
  1204.   }
  1205.  
  1206.   fclose(OutFile);
  1207.   OutFile = NULL;
  1208.  
  1209.   fclose(InFile);
  1210.   InFile = NULL;
  1211.  
  1212.   if (DeleteCommonOption)
  1213.     remove(InFileName);
  1214. }
  1215.  
  1216.  
  1217. void
  1218. main(argc, argv)
  1219. int argc;
  1220. char **argv;
  1221. {
  1222.   int i, x, FilenameCount, NamedMakeBSS;
  1223.   int FoundAny;
  1224.   long Index;
  1225.  
  1226.   static char FilenameBuffer[MAX_FILENAME_LENGTH + 1];
  1227.  
  1228.  
  1229.   printf(VERSION "\n");
  1230.  
  1231. #if 0
  1232.   /* All these things should already be zeroed because they are BSS or
  1233.      zeroed DATA but if main() somehow got called again... */
  1234.  
  1235.   CommonFilename = NULL;
  1236.   CommonOption   = 0;
  1237.   VerboseOption = 0;
  1238.   MakeBSSOption = 0;
  1239.   SymbolsOption = 0;
  1240.   DeleteCommonOption = 0;
  1241.  
  1242.   InFileName  = NULL;
  1243.   OutFileName = NULL;
  1244.  
  1245.   InFile     = NULL;
  1246.   OutFile    = NULL;
  1247.   CommonFile = NULL;
  1248.  
  1249.   TextRelocInfo    = NULL;
  1250.   DataRelocInfo    = NULL;
  1251.   SymbolTable      = NULL;
  1252.   StringTable      = NULL;
  1253.   TextRefListRoots = NULL;
  1254.   DataRefListRoots = NULL;
  1255.   TextRefLists     = NULL;
  1256.   DataRefLists     = NULL;
  1257.   DataRefXRef      = NULL;
  1258.   CommonNames      = NULL;
  1259.  
  1260.   MkBssSizes  = NULL;
  1261.   MkBssNames  = NULL;
  1262.   StringTable = NULL;
  1263.   XRef        = NULL;
  1264. #endif
  1265.  
  1266.   if (argc == 0) exit(0);
  1267.  
  1268.   /*
  1269.    *  Get the base of the name on the command line.
  1270.    */
  1271.  
  1272.   ProgramName = argv[0] + strlen(argv[0]);
  1273.  
  1274.   while(--ProgramName > argv[0])
  1275.     if (*ProgramName == '/' || *ProgramName == ':') {
  1276.       ++ProgramName;
  1277.       break;
  1278.     }
  1279.  
  1280.   /*
  1281.    *  Set 'NamedMakeBSS' to TRUE if the program's name is 'makebss'.
  1282.    */
  1283.  
  1284.   {
  1285.     char *c1 = ProgramName;
  1286.     char *c2 = "MAKEBSS";
  1287.  
  1288.     NamedMakeBSS = TRUE;
  1289.  
  1290.     while (*c1 && *c2) {
  1291.  
  1292.       /* Note: toupper() is a macro and it's argument is evaluated
  1293.          more than once. */
  1294.  
  1295.       if (toupper(*c1) != *c2) {
  1296.         NamedMakeBSS = FALSE;
  1297.         break;
  1298.       }
  1299.  
  1300.       ++c1;
  1301.       ++c2;
  1302.     }
  1303.   }
  1304.  
  1305.   /*
  1306.    *  If we were called as 'MakeBSS', act it.
  1307.    */
  1308.  
  1309.   if (NamedMakeBSS) {
  1310.  
  1311.     if (argc != 3) MkBssUsage();
  1312.  
  1313.     InFileName  = argv[1];
  1314.     OutFileName = argv[2];
  1315.  
  1316.     MakeBSS();
  1317.  
  1318.     CleanExit(NULL, RC_OK);
  1319.   }
  1320.  
  1321.   if (argc == 1) Usage();   /* Be nice if no arg's are given. */
  1322.  
  1323.   FilenameCount = 0;    /* The count of non-options */
  1324.  
  1325.   /*
  1326.    *  Parse the command line.
  1327.    */
  1328.  
  1329.   for (i = 1; i < argc; ++i) {
  1330.  
  1331.     if (argv[i][0] == OPTION_PREFIX) {
  1332.  
  1333.       switch (argv[i][1]) {
  1334.  
  1335.         case 'c':
  1336.           CommonOption = 1;
  1337.  
  1338.           if (argv[i][2] != 0) {
  1339.  
  1340.             CommonFilename = argv[i] + 2;
  1341.           }
  1342.           break;
  1343.  
  1344.         case 'C':
  1345.           CommonOption = 2;
  1346.  
  1347.           if (argv[i][2] != 0) {
  1348.  
  1349.             CommonFilename = argv[i] + 2;
  1350.           }
  1351.           break;
  1352.  
  1353.         case 'b':
  1354.           CommonOption = 3;
  1355.           break;
  1356.  
  1357.         case 'v':
  1358.           VerboseOption = 1;
  1359.           break;
  1360.  
  1361.         case 'm':
  1362.           MakeBSSOption = 1;
  1363.  
  1364.           if (argv[i][2] == 'd')
  1365.             DeleteCommonOption = 1;
  1366.  
  1367.           break;
  1368.  
  1369.         case 's':
  1370.           SymbolsOption = 1;
  1371.           break;
  1372.  
  1373.         default:
  1374.           fprintf(stderr, "Bad option.\n");
  1375.           Usage();
  1376.       }
  1377.     }
  1378.     else {
  1379.  
  1380.       switch (FilenameCount++) {
  1381.  
  1382.         case 0:  InFileName  = argv[i]; break;
  1383.         case 1:  OutFileName = argv[i]; break;
  1384.         default: Usage();
  1385.       }
  1386.     }
  1387.   }
  1388.  
  1389.   if (MakeBSSOption) {  /* If '-m' was specified... */
  1390.  
  1391.     if (OutFileName != NULL) Usage();   /* Only one non-option allowed. */
  1392.  
  1393.     OutFileName = InFileName;   /* That's actually the output file's name. */
  1394.  
  1395.     InFileName = CommonFilename;    /* The input if '-c' was used. */
  1396.  
  1397.     if (InFileName == NULL)
  1398.       InFileName = DefaultCommonFilename;
  1399.  
  1400.     if (OutFileName == NULL)
  1401.       OutFileName = DefaultBssFilename;
  1402.  
  1403.     MakeBSS();
  1404.  
  1405.     CleanExit(NULL, RC_OK);
  1406.   }
  1407.  
  1408.   if (InFileName == NULL) {
  1409.  
  1410.     fprintf(stderr, "No input filename.\n");
  1411.     Usage();
  1412.   }
  1413.  
  1414.   if (OutFileName == NULL) {
  1415.  
  1416.     if (strlen(InFileName) + strlen(DefaultFilenameExtension) >
  1417.         MAX_FILENAME_LENGTH)
  1418.       CleanExit("Filename is too long.", RC_FAIL);
  1419.  
  1420.     strcpy(FilenameBuffer, InFileName);
  1421.     OutFileName = strcat(FilenameBuffer, DefaultFilenameExtension);
  1422.   }
  1423.  
  1424.   InFile = fopen(InFileName, "r");
  1425.  
  1426.   if (InFile == NULL) {
  1427.     fprintf(stderr, "Can't open file \"%s\" for input.\n", InFileName);
  1428.     CleanExit(NULL, RC_FAIL);
  1429.   }
  1430.  
  1431.   /*
  1432.    *  Try to read the exec structure from the input.
  1433.    */
  1434.  
  1435.   if (fread((char *)&WorkingExec, sizeof(struct exec), 1, InFile) != 1) {
  1436.  
  1437.     /* If the input file is an Amiga object, copy it through unchanged.
  1438.        This simplifies linking Sun and Amiga objects together and isn't
  1439.        any more kludgy than this whole deal. */
  1440.  
  1441.     if (CopyIfAmigaObject())
  1442.       CleanExit(NULL, RC_OK);
  1443.  
  1444.     fprintf(stderr, "Can't read exec structure in file \"%s\".\n",
  1445.             InFileName);
  1446.     CleanExit(NULL, RC_FAIL);
  1447.   }
  1448.  
  1449.   if (WorkingExec.a_magic != SUN_MAGIC) {   /* The only magic supported */
  1450.  
  1451.     if (CopyIfAmigaObject())
  1452.       CleanExit(NULL, RC_OK);
  1453.  
  1454.     fprintf(stderr, "Bad magic number in file \"%s\".\n", InFileName);
  1455.     CleanExit(NULL, RC_FAIL);
  1456.   }
  1457.  
  1458.   if (VerboseOption > 0) {
  1459.  
  1460.     printf("exec:\n");
  1461.  
  1462.     printf("  dynamic     = 0x%X\n", (int)WorkingExec.a_dynamic);
  1463.     printf("  toolversion = 0x%X\n", (int)WorkingExec.a_toolversion);
  1464.     printf("  machtype    = 0x%X\n", (int)WorkingExec.a_machtype);
  1465.     printf("  text        = 0x%lX\n", WorkingExec.a_text);
  1466.     printf("  data        = 0x%lX\n", WorkingExec.a_data);
  1467.     printf("  bss         = 0x%lX\n", WorkingExec.a_bss);
  1468.     printf("  syms        = 0x%lX\n", WorkingExec.a_syms);
  1469.     printf("  entry       = 0x%lX\n", WorkingExec.a_entry);
  1470.     printf("  trsize      = 0x%lX\n", WorkingExec.a_trsize);
  1471.     printf("  drsize      = 0x%lX\n", WorkingExec.a_drsize);
  1472.  
  1473.     printf("\n");
  1474.   }
  1475.  
  1476.   /* Skip to the relocation info first. */
  1477.   fseek(InFile, sizeof(struct exec) +
  1478.                 WorkingExec.a_text + WorkingExec.a_data, SEEK_SET);
  1479.  
  1480.   /*
  1481.    *  Get the text and data relocation info.
  1482.    */
  1483.  
  1484.   if (WorkingExec.a_trsize != 0) {
  1485.  
  1486.     ALLOCATE_MEMORY(TextRelocInfo, WorkingExec.a_trsize, 1);
  1487.  
  1488.     if (fread((char *)TextRelocInfo, 1, WorkingExec.a_trsize, InFile) !=
  1489.         WorkingExec.a_trsize)
  1490.       CleanExit("Can't read text relocation info.", RC_FAIL);
  1491.   }
  1492.  
  1493.   if (WorkingExec.a_drsize != 0) {
  1494.  
  1495.     ALLOCATE_MEMORY(DataRelocInfo, WorkingExec.a_drsize, 1);
  1496.  
  1497.     if (fread((char *)DataRelocInfo, 1, WorkingExec.a_drsize, InFile) !=
  1498.         WorkingExec.a_drsize)
  1499.       CleanExit("Can't read data relocation info.", RC_FAIL);
  1500.   }
  1501.  
  1502.   /*
  1503.    *  Get the symbol table.
  1504.    */
  1505.  
  1506.   if (WorkingExec.a_syms != 0) {
  1507.  
  1508.     ALLOCATE_MEMORY(SymbolTable, WorkingExec.a_syms, 1);
  1509.  
  1510.     if (fread((char *)SymbolTable, 1, WorkingExec.a_syms, InFile) !=
  1511.         WorkingExec.a_syms)
  1512.       CleanExit("Can't read symbol table.", RC_FAIL);
  1513.   }
  1514.  
  1515.   /*
  1516.    *  Get the symbols' names.
  1517.    */
  1518.  
  1519.   /* Find the size of the table. */
  1520.   if (fread((char *)&StringTableSize, 4, 1, InFile) != 1)
  1521.     CleanExit("Can't read string table size.", RC_FAIL);
  1522.  
  1523.   ALLOCATE_MEMORY(StringTable, StringTableSize, 1);
  1524.  
  1525.   if (fread((char *)StringTable + 4, 1, StringTableSize - 4, InFile) !=
  1526.       StringTableSize - 4)
  1527.     CleanExit("Can't read string table.", RC_FAIL);
  1528.  
  1529.   /*
  1530.    *  Find out how many of these things we have.
  1531.    *
  1532.    */
  1533.  
  1534.   TextRelocCount = WorkingExec.a_trsize / sizeof(struct reloc_info_68k);
  1535.   DataRelocCount = WorkingExec.a_drsize / sizeof(struct reloc_info_68k);
  1536.   SymbolCount = WorkingExec.a_syms / sizeof(struct nlist);
  1537.  
  1538.   /*
  1539.    *  For each symbol, make a list of references to external symbols.
  1540.    *
  1541.    */
  1542.  
  1543.  
  1544.   if (SymbolCount != 0) {
  1545.  
  1546.     /* Allocate memory for the roots. */
  1547.     ALLOCATE_MEMORY(TextRefListRoots, SymbolCount,    4);
  1548.     ALLOCATE_MEMORY(DataRefListRoots, SymbolCount,    4);
  1549.  
  1550.     /* Allocate memory for the lists. */
  1551.  
  1552.     if (TextRelocCount != 0)
  1553.       ALLOCATE_MEMORY(TextRefLists,     TextRelocCount, 4);
  1554.  
  1555.     if (DataRelocCount != 0)
  1556.       ALLOCATE_MEMORY(DataRefLists,     DataRelocCount, 4);
  1557.  
  1558.     for (i = 0; i < SymbolCount; ++i) {
  1559.  
  1560.       /* Relocate the symbol name ponters. */
  1561.       if (SymbolTable[i].n_un.n_strx != 0)
  1562.         SymbolTable[i].n_un.n_strx += (unsigned long)StringTable;
  1563.  
  1564.       /* Initialize the roots to be -1, meaning empty list. */
  1565.       TextRefListRoots[i] = -1;
  1566.       DataRefListRoots[i] = -1;
  1567.     }
  1568.  
  1569.  
  1570.     FindRefs(N_TEXT);
  1571.  
  1572.     FindRefs(N_DATA);
  1573.   }
  1574.  
  1575.   /*
  1576.    *  Figure the number of each hunk in the output file.
  1577.    */
  1578.  
  1579.   x = 0;
  1580.   if (WorkingExec.a_text != 0) { CodeHunkNumber = x; ++x; }
  1581.   if (WorkingExec.a_data != 0) { DataHunkNumber = x; ++x; }
  1582.   if (WorkingExec.a_bss  != 0) { BssHunkNumber  = x; ++x; }
  1583.  
  1584.   /*
  1585.    *  Write the output file.
  1586.    */
  1587.  
  1588.   OpenOutputFile();
  1589.  
  1590.   /* Unnamed program unit. */
  1591.   WRITE_LONG(HUNK_UNIT, OutFile);
  1592.   WRITE_LONG(0, OutFile);
  1593.  
  1594.   /*
  1595.    *  Output the CODE, DATA and BSS hunks.
  1596.    */
  1597.  
  1598.   if (WorkingExec.a_text != 0) {
  1599.  
  1600.     CopySegments(N_TEXT);
  1601.  
  1602.     OutputRelocInfo(TextRelocInfo, TextRelocCount);
  1603.  
  1604.     OutputExternInfo(TextRelocInfo, TextRefListRoots, TextRefLists, N_TEXT);
  1605.  
  1606.     if (SymbolsOption) OutputSymbols(N_TEXT);
  1607.  
  1608.     WRITE_LONG(HUNK_END, OutFile);
  1609.   }
  1610.  
  1611.   if (WorkingExec.a_data != 0) {
  1612.  
  1613.     CopySegments(N_DATA);
  1614.  
  1615.     OutputRelocInfo(DataRelocInfo, DataRelocCount);
  1616.  
  1617.     OutputExternInfo(DataRelocInfo, DataRefListRoots, DataRefLists, N_DATA);
  1618.  
  1619.     if (SymbolsOption) OutputSymbols(N_DATA);
  1620.  
  1621.     WRITE_LONG(HUNK_END, OutFile);
  1622.   }
  1623.  
  1624.   if (WorkingExec.a_bss != 0) {
  1625.  
  1626.     WRITE_LONG(HUNK_BSS, OutFile);
  1627.  
  1628.     WRITE_LONG(WorkingExec.a_bss, OutFile);
  1629.  
  1630.     OutputExternDefInfo(N_BSS, FALSE);
  1631.  
  1632.     if (SymbolsOption) OutputSymbols(N_BSS);
  1633.  
  1634.     WRITE_LONG(HUNK_END, OutFile);
  1635.   }
  1636.  
  1637.   /* We're done with the input file. */
  1638.   fclose(InFile);
  1639.   InFile = NULL;
  1640.  
  1641.   /*
  1642.    *   Output absolute external definitions.  Output common block
  1643.    *   definitions if aproprate.  These things are done in a seperate hunk
  1644.    *   with no HUNK_CODE, ..DATA, or ..BSS.
  1645.    */
  1646.  
  1647.   FoundAny = FALSE;
  1648.  
  1649.   for (i = 0; i < SymbolCount; ++i) {
  1650.  
  1651.     if ((SymbolTable[i].n_type & (N_TYPE | N_EXT)) == (N_ABS | N_EXT)) {
  1652.  
  1653.       if (!FoundAny) {
  1654.  
  1655.         WRITE_LONG(HUNK_EXT, OutFile);
  1656.  
  1657.         FoundAny = TRUE;
  1658.       }
  1659.  
  1660.       OutputSymbolName(SymbolTable[i].n_un.n_name, EXT_ABS);
  1661.  
  1662.       WRITE_LONG(SymbolTable[i].n_value, OutFile);
  1663.     }
  1664.   }
  1665.  
  1666.   if (CommonOption == 0) {
  1667.  
  1668.     for (i = 0; i < SymbolCount; ++i) {
  1669.  
  1670.       if ((SymbolTable[i].n_type & (N_TYPE | N_EXT)) == (N_UNDF | N_EXT) &&
  1671.           SymbolTable[i].n_value != 0) {
  1672.  
  1673.         if (!FoundAny) {
  1674.  
  1675.           WRITE_LONG(HUNK_EXT, OutFile);
  1676.  
  1677.           FoundAny = TRUE;
  1678.         }
  1679.  
  1680.         OutputSymbolName(SymbolTable[i].n_un.n_name, EXT_COMMON);
  1681.  
  1682.         WRITE_LONG(SymbolTable[i].n_value, OutFile);
  1683.  
  1684.         WRITE_LONG(0, OutFile);
  1685.       }
  1686.     }
  1687.   }
  1688.  
  1689.   if (FoundAny) {
  1690.  
  1691.     WRITE_LONG(0, OutFile);
  1692.  
  1693.     WRITE_LONG(HUNK_END, OutFile);
  1694.   }
  1695.  
  1696.   /* Ho hum. */
  1697.  
  1698.   if (CommonOption >= 1 && CommonOption <= 2)
  1699.     StupidCommonKludge();
  1700.  
  1701.   if (CommonOption == 3)
  1702.     OutputCommonAsBss();
  1703.  
  1704.   fclose(OutFile);
  1705.   OutFile = NULL;
  1706.  
  1707.   if (VerboseOption > 0) {  /* This mind intentionally left blank. */
  1708.  
  1709.     printf("%ld symbols.\n", SymbolCount);
  1710.  
  1711.     for (i = 0; i < SymbolCount; ++i) {
  1712.  
  1713.       x = 0;
  1714.       Index = TextRefListRoots[i];
  1715.  
  1716.       while (Index >= 0) {
  1717.         Index = TextRefLists[Index];
  1718.         ++x;
  1719.       }
  1720.  
  1721.       printf("%3d %s\n", x, SymbolTable[i].n_un.n_name);
  1722.     }
  1723.  
  1724.     printf("\n%ld Text Relocations.\n", TextRelocCount);
  1725.  
  1726.     for (i = 0; i < TextRelocCount; ++i) {
  1727.  
  1728.       Index = TextRelocInfo[i].r_symbolnum;
  1729.  
  1730.       printf("%08lX %1d %1d %1d %1d %1d %1d ",
  1731.              TextRelocInfo[i].r_address,
  1732.              TextRelocInfo[i].r_pcrel,
  1733.              TextRelocInfo[i].r_length,
  1734.              TextRelocInfo[i].r_extern,
  1735.              TextRelocInfo[i].r_baserel,
  1736.              TextRelocInfo[i].r_jmptable,
  1737.              TextRelocInfo[i].r_relative);
  1738.  
  1739.       if (TextRelocInfo[i].r_extern == 1) {
  1740.  
  1741.         printf("%s\n", SymbolTable[Index].n_un.n_name);
  1742.       }
  1743.       else {
  1744.  
  1745.         printf("n_type = %02lX\n", Index);
  1746.       }
  1747.     }
  1748.  
  1749.     printf("\n%ld Data Relocations.\n", DataRelocCount);
  1750.  
  1751.     for (i = 0; i < DataRelocCount; ++i) {
  1752.  
  1753.       Index = DataRelocInfo[i].r_symbolnum;
  1754.  
  1755.       printf("%08lX %1d %1d %1d %1d %1d %1d ",
  1756.              DataRelocInfo[i].r_address,
  1757.              DataRelocInfo[i].r_pcrel,
  1758.              DataRelocInfo[i].r_length,
  1759.              DataRelocInfo[i].r_extern,
  1760.              DataRelocInfo[i].r_baserel,
  1761.              DataRelocInfo[i].r_jmptable,
  1762.              DataRelocInfo[i].r_relative);
  1763.  
  1764.       if (DataRelocInfo[i].r_extern == 1) {
  1765.  
  1766.         printf("%s\n", SymbolTable[Index].n_un.n_name);
  1767.       }
  1768.       else {
  1769.  
  1770.         printf("n_type = %02lX\n", Index);
  1771.       }
  1772.     }
  1773.   }
  1774.  
  1775.   CleanExit(NULL, RC_OK);
  1776. }
  1777.  
  1778.